
/**
 * @author lyj
 *
 */
const flinkJsonToGraphXml = (function() {
  this.version = '1.0.0'
  this.mMxUtils = null
  this.mGlobal = null
  this.mMxCell = null
  this.mMxGeometry = null
  this.mMxPoint = null
  // json对象转xml对象
  this.flinkJsonToGraphXml = function(mxCell, mxGeometry, mxPoint, argMxUtils, argGlobal, lNewModel, flinkJson) {
    this.mMxUtils = argMxUtils
    this.mGlobal = argGlobal
    this.mMxCell = mxCell
    this.mMxGeometry = mxGeometry
    this.mMxPoint = mxPoint

    var doc = argMxUtils.createXmlDocument()

    // Create the return object
    lNewModel.createRoot()
    var lNRoot = lNewModel.getRoot()
    // 创建默认节点，info
    const lInfor = this.funCreateUserDefinedDefaultParentElement('transformation')
    const parent = lNewModel.getChildAt(lNRoot, 0)
    parent.value = lInfor
    // 为hop提供数据
    const lStepInfor = []
    let lElementID = 4
    // 创建自定义标签 step
    const lFlinkStepList = flinkJson.model.step
    for (let i = 0; i < lFlinkStepList.length; i++) {
      // 如：tableInput，根据该类型，进行本地化处理
      const lStepType = lFlinkStepList[i].type
      // 如：表输入，组件的名称
      const lStepName = lFlinkStepList[i].name
      // 连接信息
      const lStepConnection = lFlinkStepList[i].connection
      // 表名称
      const lStepTableName = lFlinkStepList[i].tableName
      // 2023年12月25日 修改xy坐标，由保存传入参数获取
      const lStepGeometryX = lFlinkStepList[i].x
      const lStepGeometryY = lFlinkStepList[i].y
      // 为hop提供数据
      const lStepInforItem = { name: lStepName, stepId: '', inputItem: null, outPutItem: null }
      // 需要sql 节点的场合
      const lStepSql = this.funCreateStepSql(lFlinkStepList[i].fields, lStepTableName)
      const lTableFieldData = this.funCreateTableFieldsData(lFlinkStepList[i].fields)
      let lSrcTableName = ''
      let lSqlForm = null
      if (lStepConnection) {
        lSrcTableName = lStepConnection.name + '.' + lStepTableName
        lSqlForm = { 'src': lStepConnection.id, 'srcName': lStepConnection.name, 'schema': lStepConnection.name, 'tableName': lStepTableName, 'srcTableName': lSrcTableName }
      }
      // 组织本地化组件基本数据
      const formData = {
        type: lStepType,
        name: lStepName,
        sql: lStepSql,
        connection: lStepConnection,
        table: { id: '', name: lStepTableName },
        tableFieldsData: lTableFieldData,
        connectionName: '', // 备用
        lazy_conversion_active: 'N', // 允许简易转换
        variables_active: 'N', // 替换SQL语句里的变量
        lookup: '',
        excute_each_row: 'N', // 执行每一行
        limit: 0, // 限制记录数量 0为不限制
        sqlForm: lSqlForm,
        field_to_use: lFlinkStepList[i].field_to_use, // 使⽤的字段名,提供接⼝获取
        target_field: lFlinkStepList[i].target_field, // ⽬标字段名(空=覆盖)
        non_mathch_default: lFlinkStepList[i].non_mathch_default, // 不匹配时默认值
        split_field: lFlinkStepList[i].split_field, // 拆分字段，提供接⼝获取
        delimiter: lFlinkStepList[i].delimiter, // 拆分字段分割符
        join_type: lFlinkStepList[i].join_type, // 连接类型
        step1: lFlinkStepList[i].step1, // 第⼀个步骤，提供接⼝，下拉框选择
        step2: lFlinkStepList[i].step2, // 第⼆个步骤，提供接⼝，下拉框选择
        executeType: lFlinkStepList[i].executeType, // 执⾏⽅式，最先执⾏：before;最后执⾏
        inputType: lFlinkStepList[i].inputType, // 输⼊类型
        primaryKey: lFlinkStepList[i].primaryKey, // 主键
        tableName: lFlinkStepList[i].tableName, // topic名称
        url: lFlinkStepList[i].url, // kafka地址
        calc_type: lFlinkStepList[i].calc_type,
        fields: lFlinkStepList[i].fields
      }
      // 创建本地化组件
      const lLocalStepType = this.funCreateStepType(lStepType)
      var vNewStepItem = this.funCreateDefinedElementStep({ name: lStepName, type: lLocalStepType.type, pluginId: lLocalStepType.pluginId })
      const lBaseStyle = 'step;' + lLocalStepType.baseStyle
      // 2023年12月25日 修改xy坐标，由保存传入参数获取
      const lX = lStepGeometryX // 90 + (i * 2 * 90)
      const lY = lStepGeometryY // 50
      const lStepItem = new mxCell(vNewStepItem, new mxGeometry(lX, lY, 48, 48), lBaseStyle)
      // 创建本地组件基本属性
      const data = doc.createElement(argGlobal.SAVE_FORMDATA_ELEMENT)
      data.setAttribute(argGlobal.SAVE_FORMDATA_ELEMENT_ATTRIBUTE, JSON.stringify(formData))
      lStepItem.value.appendChild(data)
      lElementID++
      lStepItem.setId(lElementID)
      // 为hop提供数据
      lStepInforItem.stepId = lElementID
      lStepItem.setAttribute(argGlobal.ELEMENT_DEFAULT_ATTRIBUTE_NAME, formData.name)
      lStepItem.isVertex()
      lStepItem.setVertex('1')
      // 将组件插入root
      lNRoot.insert(lStepItem)
      // 设置本组件的父节点
      const SeptParent = lNewModel.getChildAt(lNRoot, 0)
      lStepItem.setParent(SeptParent)
      // =========================================================================
      // 创建本组件的指向性节点 Input
      const lInputGeometry = new mxGeometry(0, 0.5, 16, 16)
      const lInputPoint = new mxPoint(-8, -8)
      lInputGeometry.offset = lInputPoint
      // lInputGeometry.setTerminalPoint(lInputPoint)
      lInputGeometry.relative = true
      const lStepItemInput = new mxCell('Input', lInputGeometry, 'port;port-input')
      lElementID++
      lStepItemInput.setId(lElementID)
      lStepItemInput.isVertex()
      lStepItemInput.setVertex('1')
      lNRoot.insert(lStepItemInput)
      lStepItemInput.setParent(lStepItem)
      // 为hop提供数据
      lStepInforItem.inputItem = lStepItemInput
      // 创建本组件的指向性节点 Output
      const lOutputGeometry = new mxGeometry(0, 0.5, 16, 16)
      const lOutputPoint = new mxPoint(40, -8)
      lOutputGeometry.offset = lOutputPoint
      // lInputGeometry.setTerminalPoint(lInputPoint)
      lOutputGeometry.relative = true
      const lStepItemOutput = new mxCell('Output', lOutputGeometry, 'port;port-output')
      lElementID++
      lStepItemOutput.setId(lElementID)
      lStepItemOutput.isVertex()
      lStepItemOutput.setVertex('1')
      lNRoot.insert(lStepItemOutput)
      lStepItemOutput.setParent(lStepItem)
      // 为hop提供数据
      lStepInforItem.outPutItem = lStepItemOutput
      lStepInfor.push(lStepInforItem)
    }
    // =========================================================================
    // 创建本地组件 关系节点 hop
    const lFlinkHopList = flinkJson.model.hop
    for (let i = 0; i < lFlinkHopList.length; i++) {
      const lFromName = lFlinkHopList[i].from
      const lToName = lFlinkHopList[i].to
      var doc = argMxUtils.createXmlDocument()
      var edgeObj = doc.createElement(argGlobal.EDGE_ELEMENT)
      const edge = null
      // 默认连线有效 enable=Y
      edgeObj.setAttribute(argGlobal.EDGE_ELEMENT_ATTRIBUTE_ENABLED, argGlobal.EDGE_ELEMENT_ATTRIBUTE_ENABLED_TRUE_VALUE)

      const lHopGeometry = new mxGeometry(0, 0, 0, 0)
      lHopGeometry.relative = true
      // const lStepItemInput = new mxCell('', lHopGeometry, 'hop')
      // lStepItemInput.isEdge = true
      const lHopItem = new mxCell(edgeObj, lHopGeometry, 'hop')
      lElementID++
      lHopItem.setId(lElementID)
      // lHopItem.isEdge = true
      lHopItem.setEdge(true)
      lNRoot.insert(lHopItem)
      const SeptParent = lNewModel.getChildAt(lNRoot, 0)
      lHopItem.setParent(SeptParent)
      // 查询source target
      let lOuptputSource = null
      let lInputTarget = null
      for (let j = 0; j < lStepInfor.length; j++) {
        if (lStepInfor[j].name === lFromName) {
          lOuptputSource = lStepInfor[j].outPutItem
          continue
        }
        if (lStepInfor[j].name === lToName) {
          lInputTarget = lStepInfor[j].inputItem
        }
      }
      lHopItem.source = lOuptputSource
      lHopItem.target = lInputTarget
    }

    return lNewModel
  },
  // 创建组件
  this.funCreateDefinedElementStep = function(plugin) {
    var element = null
    var doc = this.mMxUtils.createXmlDocument()
    element = doc.createElement(this.mGlobal.TRANS_ELEMENT)
    // 默认属性
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_NAME, plugin.name)
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_TYPE, plugin.type)
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_PLUGIN_ID, plugin.pluginId)
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_DESCRIPTION, '')
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_DISTRIBUTE, 'Y')
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_CUSTOM_DISTRIBUTION, '')
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_COPIES, 1)
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_PARTITIONING, '')
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_ATTRIBUTES, '')
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_CLUSTER_SCHEMA, '')
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_REMOTESTEPS, '')
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_DRAW, 'Y')
    element.setAttribute(this.mGlobal.ELEMENT_DEFAULT_ATTRIBUTE_PARALLEL, 'N')

    // start dummy组件上添加start,dummy属性进行区分
    if (plugin.pluginId === 'start') {
      element.setAttribute('start', 'Y')
      element.setAttribute('dummy', 'N')
    } else if (plugin.pluginId === 'dummy') {
      element.setAttribute('start', 'N')
      element.setAttribute('dummy', 'Y')
    }
    return element
  },
  this.funCreateUserDefinedDefaultParentElement = function(type) {
    var doc = this.mMxUtils.createXmlDocument()
    var parentElement = doc.createElement(this.mGlobal.PARENT_ELEMENT)
    parentElement.setAttribute(this.mGlobal.PARENT_ELEMENT_ATTRIBUTE_NAME, '')
    parentElement.setAttribute(this.mGlobal.PARENT_ELEMENT_ATTRIBUTE_TYPE, type)
    parentElement.setAttribute(this.mGlobal.PARENT_ELEMENT_ATTRIBUTE_DIRECTORY, '/')

    return parentElement
  },
  // 根据flink返回的字段，创建本地化查询语句
  this.funCreateStepSql = function(argFlinkFields, argTableName) {
    let lSql = ''
    if (argFlinkFields === undefined || argFlinkFields === null || argFlinkFields.length <= 0 ||
            argTableName === undefined || argTableName === null || argTableName === '') {
      return lSql
    }
    for (let i = 0; i < argFlinkFields.length; i++) {
      const lColumnKey = Object.keys(argFlinkFields[i])[0]
      if (lSql === '') {
        lSql = argFlinkFields[i][lColumnKey]
      } else {
        lSql = lSql + ',' + argFlinkFields[i][lColumnKey]
      }
    }
    return 'SELECT ' + lSql + ' FROM ' + argTableName
  },
  // 根据flink返回的字段，创建本地化字段信息
  this.funCreateTableFieldsData = function(argFlinkFields) {
    const lTableFieldsData = []
    if (argFlinkFields === undefined || argFlinkFields === null || argFlinkFields.length <= 0) {
      return lTableFieldsData
    }
    for (let i = 0; i < argFlinkFields.length; i++) {
      const lColumnKey = Object.keys(argFlinkFields[i])[0]
      const lFieldItem = {
        'name': argFlinkFields[i][lColumnKey],
        'type': 'varchar',
        'comment': '',
        'keyFlag': false,
        'autoIncrement': false,
        'defaultValue': null,
        'javaType': 'STRING',
        'columnFamily': null,
        'position': i,
        'precision': 0,
        'scale': 0,
        'characterSet': 'utf8',
        'collation': 'utf8_general_ci',
        'nullable': false,
        'flinkType': 'STRING'
      }
      lTableFieldsData.push(lFieldItem)
    }

    return lTableFieldsData
  },
  // 根据flink返回的组件类型，获取本地化组件类型
  this.funCreateStepType = function(argFlinkStepType) {
    const lStepType = { type: '', pluginId: 'table-input', baseStyle: '' }
    switch (argFlinkStepType) {
      case 'UniqueRowsByHashSet':
        lStepType.type = 'Unique'
        lStepType.pluginId = 'unique-rows'
        lStepType.baseStyle = 'trans-unique-rows'
        break
      case 'ValueMapper':
        lStepType.type = 'ValueMapper'
        lStepType.pluginId = 'value-mapper'
        lStepType.baseStyle = 'trans-value-mapper'
        break
      case 'Calculator':
        lStepType.type = 'Calculator'
        lStepType.pluginId = 'calculator'
        lStepType.baseStyle = 'trans-calculator'
        break
      case 'Constant':
        lStepType.type = 'Constant'
        lStepType.pluginId = 'constant'
        lStepType.baseStyle = 'trans-constant'
        break
      case 'DataValidator':
        lStepType.type = 'DataValidator'
        lStepType.pluginId = 'data-validator'
        lStepType.baseStyle = 'trans-data-validator'
        break
      case 'ExecSQL':
        lStepType.type = 'ExecSQL'
        lStepType.pluginId = 'exec-sql'
        lStepType.baseStyle = 'trans-exec-sql'
        break
      case 'FieldSplitter':
        lStepType.type = 'FieldSplitter'
        lStepType.pluginId = 'field-splitter'
        lStepType.baseStyle = 'trans-field-splitter'
        break
      case 'kafkaInput':
        lStepType.type = 'kafkaInput'
        lStepType.pluginId = 'kafka-input'
        lStepType.baseStyle = 'trans-kafka-input'
        break
      case 'kafkaOutput':
        lStepType.type = 'kafkaOutput'
        lStepType.pluginId = 'kafka-output'
        lStepType.baseStyle = 'trans-kafka-output'
        break
      case 'MergeJoin':
        lStepType.type = 'MergeJoin'
        lStepType.pluginId = 'merge-join'
        lStepType.baseStyle = 'trans-merge-join'
        break
      case 'IfNull':
        lStepType.type = 'IfNull'
        lStepType.pluginId = 'null-replace'
        lStepType.baseStyle = 'trans-null-replace'
        break
      case 'NullValidator':
        lStepType.type = 'NullValidator'
        lStepType.pluginId = 'null-validator'
        lStepType.baseStyle = 'trans-null-validator'
        break
      case 'NumberRangeValidator':
        lStepType.type = 'NumberRangeValidator'
        lStepType.pluginId = 'range-validator'
        lStepType.baseStyle = 'trans-range-validator'
        break
      case 'ReplaceString':
        lStepType.type = 'ReplaceString'
        lStepType.pluginId = 'replace-string'
        lStepType.baseStyle = 'trans-replace-string'
        break
      case 'EncryptionMasking':
        lStepType.type = 'EncryptionMasking'
        lStepType.pluginId = 'sm3'
        lStepType.baseStyle = 'trans-sm3'
        break
      case 'EncryptionMasking1':
        lStepType.type = 'EncryptionMasking'
        lStepType.pluginId = 'sm4'
        lStepType.baseStyle = 'trans-sm4'
        break
      case 'StringOperations':
        lStepType.type = 'StringOperations'
        lStepType.pluginId = 'string-operations'
        lStepType.baseStyle = 'trans-string-operations'
        break
      case 'tableInput':
        lStepType.type = 'TableInput'
        lStepType.pluginId = 'table-input'
        lStepType.baseStyle = 'trans-table-input'
        break
      case 'tableOutput':
        lStepType.type = 'TableOutput'
        lStepType.pluginId = 'table-output'
        lStepType.baseStyle = 'trans-table-output'
        break
      case 'UrlValidator':
        lStepType.type = 'UrlValidator'
        lStepType.pluginId = 'url-validator'
        lStepType.baseStyle = 'trans-url-validator'
        break
      default:
        break
    }
    return lStepType
  }

  return this
}.call({}))

export default flinkJsonToGraphXml

// if (typeof module !== 'undefined' && module !== null && module.exports)
//   module.exports = flinkJsonToGraphXml
// else if (typeof define === 'function' && define.amd)
//   define(function() { return flinkJsonToGraphXml })
